package com.ruoyi.collection.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.bizsys.domain.LoanDeferredOrder;
import com.ruoyi.bizsys.domain.LoanIou;
import com.ruoyi.bizsys.domain.LoanIouDeferred;
import com.ruoyi.bizsys.domain.ProductDeferredInfo;
import com.ruoyi.bizsys.mapper.LoanIouDeferredMapper;
import com.ruoyi.bizsys.service.ILoanDeferredOrderService;
import com.ruoyi.bizsys.service.ILoanIouDeferredService;
import com.ruoyi.bizsys.service.ILoanIouService;
import com.ruoyi.bizsys.service.IProductDeferredInfoService;
import com.ruoyi.collection.domain.LoanDeferredOrderVO;
import com.ruoyi.collection.domain.ProductDeferredVO;
import com.ruoyi.collection.service.IDeferredService;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.Func;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class DeferredServiceImpl implements IDeferredService {

    @Autowired
    private ILoanIouService loanIouService;
    @Autowired
    private ILoanDeferredOrderService loanDeferredOrderService;
    @Autowired
    private ProcessForIouDefferredService processForIouDefferredService;
    @Autowired
    private LoanIouDeferredMapper loanIouDeferredMapper;
    @Autowired
    private ILoanIouDeferredService loanIouDeferredService;
    @Autowired
    private IProductDeferredInfoService productDeferredInfoService;

    public static final DecimalFormat currency = new DecimalFormat("#0.00");

    @Override
    public JSONObject findTodayBuyDeferredInfoByLoanNos(List<String> loanNos) {
        List<String> todayBuyDefLoanNos = loanIouDeferredMapper.findTodayDeferredByLoanNos(loanNos);
        Map<String, BigDecimal> loanRemainingAmountMap = getLoanRemainingAmount(todayBuyDefLoanNos);

        List<String> queryParams;
        if (Func.isEmpty(todayBuyDefLoanNos)) {
            queryParams = loanNos;
        } else {
            // 过滤今天已购买过延期产品的借据号
            queryParams = loanNos.stream().filter(item -> !todayBuyDefLoanNos.contains(item)).collect(Collectors.toList());
        }
        // 有可用金融包购买的借据列表
        List<String> haveDeferredLoanNos = filterHaveDeferredLoanNos(queryParams);

        JSONObject jsonObject = new JSONObject();
        JSONArray jsonArray = new JSONArray();

        for (String loanNo : loanNos) {
            JSONObject itemJson = new JSONObject();
            itemJson.put("loanNo", loanNo);
            itemJson.put("clickFlag", haveDeferredLoanNos.contains(loanNo));
            if (loanRemainingAmountMap.containsKey(loanNo)) {
                itemJson.put("remainingAmount", String.valueOf(loanRemainingAmountMap.get(loanNo).setScale(2, BigDecimal.ROUND_HALF_UP)));
            }
            //查询借据延期订单
            itemJson.put("deferredLoanList",this.getDeferredLoanList(loanNo));
            jsonArray.add(itemJson);
        }
        jsonObject.put("tableList", jsonArray);
        return jsonObject;
    }

    /**
     * 获取一个借据的延期订单信息
     * @param loanNo
     * @return
     */
    private List<LoanDeferredOrderVO> getDeferredLoanList(String loanNo){
        //查询原始借据信息
        LoanIou loanIou = loanIouService.getOne(new LambdaQueryWrapper<LoanIou>().eq(LoanIou::getLoanSerialNo,loanNo).last(" limit 1"));
        assert loanIou!=null;
        //查询借据的延期订单列表
        List<LoanDeferredOrder> loanDeferredOrderList = loanDeferredOrderService.list(
                new LambdaQueryWrapper<LoanDeferredOrder>()
                        .eq(LoanDeferredOrder::getLoanSerialNo,loanNo) //原始借据号
                        .eq(LoanDeferredOrder::getState,UserConstants.BUSINESS_NORMAL) //正常状态
                        .orderByDesc(LoanDeferredOrder::getCreateTime)  //按创建时间排序
        );
        if(CollectionUtils.isEmpty(loanDeferredOrderList)){
            return new ArrayList<>();
        }
        return loanDeferredOrderList.stream().map(obj-> {
            LoanDeferredOrderVO loanDeferredOrderVO = new LoanDeferredOrderVO();
            BeanUtils.copyProperties(obj,loanDeferredOrderVO);
            //原始借据还款到期日+延期订单延期天数等于本延期订单的还款到期日
            loanDeferredOrderVO.setDeferRepaymentDate(DateUtils.getNewDayV2(loanIou.getRepayDate(), obj.getNumDeferredDay()));
            //创建时间
            loanDeferredOrderVO.setApplicationDate(DateUtils.formatDate(obj.getCreateTime(),DateUtils.DD_MM_YYYY_SLASH));
            return loanDeferredOrderVO;
        }).collect(Collectors.toList());
    }

    /**
     * 获取有可购延期金融产品的借据号列表
     * @param loanNos
     * @return
     */
    private List<String> filterHaveDeferredLoanNos(List<String> loanNos){
        if (Func.isEmpty(loanNos)) {
            return Collections.emptyList();
        }
        List<String> haveDeferredLoanNos = new ArrayList<>();
        List<ProductDeferredInfo> deferredList;
        for (String loanNo : loanNos) {
            try {
                deferredList = processForIouDefferredService.getSelectDefferreds(loanNo);
            } catch (ParseException e) {
                log.error("getDeferredByLoanNos获取延期金融包列表异常(催收按钮状态)，loanSerialNo={}", loanNo, e);
                deferredList = Collections.emptyList();
            }
            boolean flag = haveDeferred(deferredList);
            if (flag) {
                haveDeferredLoanNos.add(loanNo);
            }
        }
        return haveDeferredLoanNos;
    }

    /**
     * 是否有可购买的延期金融产品
     * @param deferredList
     * @return
     */
    private boolean haveDeferred(List<ProductDeferredInfo> deferredList){
        if (Func.isEmpty(deferredList)) {
            return false;
        }
        for (ProductDeferredInfo item : deferredList) {
            if (!item.isNeedLocked()) {
                return true;
            }
        }
        return false;
    }

    /**
     * 查询已购延期产品的借据剩余待还本金
     * @param todayBuyDefLoanNos
     * @return
     */
    private Map<String, BigDecimal> getLoanRemainingAmount(List<String> todayBuyDefLoanNos){
        if(Func.isEmpty(todayBuyDefLoanNos)) {
            return Collections.emptyMap();
        }
        QueryWrapper<LoanIou> loanIouQueryWrapper = new QueryWrapper<>();
        loanIouQueryWrapper.eq("state", UserConstants.BUSINESS_NORMAL)
                .in("loan_serial_no", todayBuyDefLoanNos)
                .select("loan_serial_no", "loan_principal", "repaid_principal");
        List<LoanIou> list = loanIouService.getBaseMapper().selectList(loanIouQueryWrapper);
        if (Func.isEmpty(list)) {
            return Collections.emptyMap();
        }
        Map<String, BigDecimal> map = new HashMap<>(list.size());
        for (LoanIou item : list) {
            map.put(item.getLoanSerialNo(), item.getLoanPrincipal().subtract(item.getRepaidPrincipal()));
        }
        return map;
    }

    @Override
    public List<ProductDeferredVO> getDeferredByLoanNo(String loanNo) {
        List<ProductDeferredVO> resultList = new ArrayList<>();
        List<ProductDeferredInfo> defferredList;
        try {
            defferredList = processForIouDefferredService.getSelectDefferreds(loanNo);
        } catch (ParseException e) {
            log.error("getDeferredByLoanNos获取延期金融包列表异常，loanSerialNo={}", loanNo, e);
            defferredList = Collections.emptyList();
        }
        buildProductDeferredVO(defferredList, loanNo, resultList);
        return resultList;
    }


    /**
     * 结果列表中填充指定借据下的所有可用延期金融包
     * @param defferredList
     * @param loanNo
     * @param resultList
     */
    private void buildProductDeferredVO(List<ProductDeferredInfo> defferredList, String loanNo, List<ProductDeferredVO> resultList){

        if (Func.isEmpty(defferredList)) {
            return;
        }
        ProductDeferredVO productDeferredVO;
        for (ProductDeferredInfo item : defferredList) {
            productDeferredVO = getProductDeferredVO(loanNo, item);
            if (Objects.isNull(productDeferredVO)) {
                continue;
            }
            resultList.add(productDeferredVO);
        }
    }

    /**
     * 根据借据详情及可用金融包组装数据
     * @param serialNo
     * @param productDeferredInfo
     * @return
     */
    private ProductDeferredVO getProductDeferredVO(String serialNo, ProductDeferredInfo productDeferredInfo){
        if (productDeferredInfo.isNeedLocked()) {
            return null;
        }
        //获取借据详情
        LoanIou loanIou = getCustomerIouByLoanSerialNo(serialNo);
        if (Objects.isNull(loanIou)) {
            return null;
        }
        return this.calculateDeferredInfo(loanIou,productDeferredInfo);
    }

    private ProductDeferredVO calculateDeferredInfo(LoanIou loanIou,ProductDeferredInfo productDeferredInfo){
        // 原始借据利息、原始借据服务费、原始借据滞纳金
        BigDecimal interestAmt = loanIou.getLoanInterest().subtract(loanIou.getRepaidInterest());
        BigDecimal serviceFee = loanIou.getServiceFee().subtract(loanIou.getRepaidServiceFee());
        BigDecimal lateFee = loanIou.getLateFee().subtract(loanIou.getRepaidLateFee());
        // 延期费 = 延期产品利息 + 延期服务费
        BigDecimal toBeRepaid = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());
        BigDecimal deferredInterest = toBeRepaid.multiply(productDeferredInfo.getInterestRate()).multiply(new BigDecimal(productDeferredInfo.getNumDeferredDay()));
        BigDecimal deferredServiceFee = toBeRepaid.multiply(productDeferredInfo.getServiceRate());
        BigDecimal extensionFree = deferredInterest.add(deferredServiceFee);
        // 选中该延期包后的还款日期、购买该金融包所需支付金额
        String baseRepayDate = Func.isEmpty(loanIou.getDeferredRepayDate()) ? loanIou.getRepayDate() : loanIou.getDeferredRepayDate();
        String repaymentDate = DateUtils.getNewDayV2(baseRepayDate, productDeferredInfo.getNumDeferredDay());
        BigDecimal needRepaidAmt = interestAmt.add(serviceFee).add(lateFee).add(extensionFree);

        ProductDeferredVO productDeferredVO = new ProductDeferredVO();
        productDeferredVO.setProductDeferredId(productDeferredInfo.getId());
        productDeferredVO.setNumDeferredDay(productDeferredInfo.getNumDeferredDay());
        productDeferredVO.setLoanSerialNo(loanIou.getLoanSerialNo());
        productDeferredVO.setDeferredRepayDate(repaymentDate);
        productDeferredVO.setMinRepay(currency.format(needRepaidAmt.setScale(2, BigDecimal.ROUND_HALF_UP)));
        productDeferredVO.setNextRepayAmount(currency.format(toBeRepaid.setScale(2, BigDecimal.ROUND_HALF_UP)));
        return productDeferredVO;
    }

    private LoanIou getCustomerIouByLoanSerialNo(String loanSerialNo) {
        QueryWrapper<LoanIou> loanIouQueryWrapper = new QueryWrapper<>();
        loanIouQueryWrapper.eq("loan_serial_no", loanSerialNo)
                .eq("state", UserConstants.BUSINESS_NORMAL)
                .last("limit 1");
        LoanIou loanIou = loanIouService.getBaseMapper().selectOne(loanIouQueryWrapper);
        if (Objects.isNull(loanIou)) {
            log.info("getCustomerIouByLoanSerialNo {}:借据不存在", loanSerialNo);
            return null;
        }
        return loanIou;
    }
}
